﻿#region Copyright and Licensing Notice
// Copyright (C) 2011 Steven Bosnick
// 
// This program is open source software; you can redistribute it 
// and/or modifiy it under the terms of the Eclipse Public License,
// version 1.0.
// 
// This program is distributed in the hope that it will be useful, 
// but WITHOUT ANY WARRANTY; without even the implied
// warranty of MERCHANTABILITY or FITNESS FOR A 
// PARTICULAR PURPOSE. See the Eclipse Public License for more
// details.
// 
// You should have received a copy of the Eclipse Public License 
// along with this program; if not, you can find a copy at
// "http://www.opensource.org/licenses/eclipse-1.0.php".
#endregion
using System;
using BitwiseOre.Properties;
using BitwiseOre.SharedMemory.Core.Common;
using BitwiseOre.SharedMemory.JetBrains;

namespace BitwiseOre.SharedMemory.Core.Primatives
{
    [UsedImplicitly]
    internal sealed class GuidQueueFactory : ISharedObjectInit, ISharedFactory<GuidQueue>
    {
        private static readonly string UnititializedCountMessage = Resources.GuidQueueFactory_UnititializedCountMessage;
        private static readonly string UnexpectedHeaderFoundMessage = Resources.GuidQueueFactory_UnexpectedHeaderFoundMessage;
        
        private readonly IAllocator _allocator;
        private readonly Func<IIntArray, IIndexQueue> _createIndexQueue;

        private int? _count;

        public GuidQueueFactory(IAllocator allocator,
                                Func<IIndexQueueLayout, IIntArray, IIndexQueue> createIndexQueue,
                                Func<IIntArray, IIndexQueueLayout> createLayout, int? count = null)
        {
            _allocator = allocator;
            _count = count;

            _createIndexQueue =
                next =>
                createIndexQueue(
                    createLayout(
                        _allocator.AllocateIntArray(QueueConstants.IndexQueueLayoutCount)),
                    next);
        }

        public void InitializeNew()
        {
            if (_count == null) throw new InvalidOperationException(UnititializedCountMessage);
            _allocator.AllocateArray<GuidQueueHeader>(1)[0] = new GuidQueueHeader(_count.Value);
        }

        public void InitializeExisting()
        {
            var header = _allocator.AllocateArray<GuidQueueHeader>(1)[0];
            if (!header.Verify()) throw new InvalidOperationException(UnexpectedHeaderFoundMessage);
            _count = header.Count;
        }

        // ReSharper disable PossibleInvalidOperationException
        public GuidQueue Create()
        {
            var pendingdequeues = _allocator.AllocateIntArray(QueueConstants.PendingDequeuesCount);
            var next = _allocator.AllocateIntArray((int) _count);
            var empty = _createIndexQueue(next);
            var full = _createIndexQueue(next);

            return new GuidQueue(full, empty, _allocator.AllocateArray<Guid>((int) _count), pendingdequeues);
        }
        // ReSharper restore PossibleInvalidOperationException
    }
}